# coding=utf-8
from __future__ import print_function, absolute_import

from datetime import timedelta

import akshare as ak
import pandas as pd
import pymysql
import talib as ta
from ewili.common.code import code_in_symbols
from gm.api import *


# 策略中必须有init方法
def init(context):
    # 使用多少的资金来进行开仓。
    context.ratio = 0.8

    # 链接数据库
    db = pymysql.connect("localhost", "root", "root", "quant_station")
    sql = "SELECT code,DATE_FORMAT(trade_date,'%Y-%m-%d') as date_trade,pb,ps,pe from stock_a_lg_indicator where pb <=0.5 and pe_ttm>0 and pe_ttm<=20 and dv_ttm>0"
    # 使用 cursor() 方法创建一个游标对象 cursor
    cursor = db.cursor()
    # 使用 execute()  方法执行 SQL 查询
    cursor.execute(sql)
    # 获取所有记录列表
    results = cursor.fetchall()
    # 执行结果转化为dataframe
    context.stocks_values = pd.DataFrame(list(results), columns=list(['code', 'date_trade', 'pb', 'ps', 'pe']))
    db.close()

    # 选股
    schedule(schedule_func=algo_select, date_rule='1d', time_rule='09:25:00')

    # 首单
    schedule(schedule_func=trade_stocks, date_rule='1d', time_rule='09:32:00')

    # 加仓单
    schedule(schedule_func=add_trade_stocks, date_rule='1d', time_rule='09:34:00')

    # 通过get_instruments获取所有的上市股票代码
    context.all_stock = get_instruments(exchanges='SHSE, SZSE', sec_types=[1], skip_suspended=False,
                                        skip_st=False, fields='symbol, listed_date, delisted_date',
                                        df=True)

    # a股破净率数据 回测使用
    context.stock_a_below_net_asset_statistics_df = ak.stock_a_below_net_asset_statistics(symbol="全部A股")
    # algo_select(context)
    # 建仓股票池
    context.trade_stocks = []


def algo_select(context):
    print("当前持仓股数量", len(context.account().positions()))
    date_net = context.now.strftime("%Y-%m-%d")
    # 市场分析
    """
        只在市场破净率大于1%时执行选股

    market_value = context.stock_a_below_net_asset_statistics_df[
        (context.stock_a_below_net_asset_statistics_df['date'] == date_net) & (
                context.stock_a_below_net_asset_statistics_df['below_net_asset_ratio'] >= 0.01)]
    if len(market_value) == 0:
        return
    """
    stocks_values = context.stocks_values[(context.stocks_values['date_trade'] == date_net)]
    if len(stocks_values) == 0:
        return

    # 获取筛选时间：date1表示当前日期之前的100天，date2表示当前时间
    date1 = (context.now - timedelta(days=100)).strftime("%Y-%m-%d %H:%M:%S")
    date2 = context.now.strftime("%Y-%m-%d %H:%M:%S")

    # 上市不足100日的新股和退市股和B股
    code = context.all_stock[
        (context.all_stock['listed_date'] < date1) & (context.all_stock['delisted_date'] > date2) & (
                context.all_stock['symbol'].str[5] != '9') & (context.all_stock['symbol'].str[5] != '2') & (
                context.all_stock['symbol'].str.startswith('688') is False)]

    # 剔除停牌
    df_code = get_history_instruments(symbols=code['symbol'].to_list(), start_date=date2, end_date=date2, df=True)
    df_code = df_code[(df_code['is_suspended'] == 0) & (df_code['sec_level'] == 1)]

    # 个股分析
    print("执行选股", " ", "预筛选股票数量：", len(stocks_values), date_net)
    for symbol in stocks_values['code']:
        can_trade = False

        symbol = code_in_symbols(symbol, df_code['symbol'])

        if symbol is None:
            continue

        history_n_data = history_n(symbol=symbol, frequency='1d', count=10000000, end_time=context.now,
                                   fields='symbol, open, close, high', adjust=ADJUST_PREV, df=True)
        print(symbol, "获取历史值完毕")
        if len(history_n_data) < 3:
            continue

        last_close = history_n_data['close'].loc[len(history_n_data) - 1]

        highest = history_n_data['high'].max()

        if last_close >= highest:
            continue

        '''
            高估价区域
        '''
        sma = ta.MA(history_n_data['close'], len(history_n_data), 0)
        mid_high = highest / 2

        if last_close >= sma[len(history_n_data) - 1] or last_close >= mid_high:
            continue

        '''
            合理估价区域
        '''
        normal_high = mid_high / 2
        normal_ma = sma[len(history_n_data) - 1] / 2

        if last_close >= normal_high or last_close >= normal_ma:
            continue
        if last_close <= normal_high and last_close <= normal_ma:
            continue

        '''
            低估价区域
        '''
        low_high = mid_high * 0.2
        low_sma = sma[len(history_n_data) - 1] * 0.2
        if last_close < low_sma or last_close < low_high:
            can_trade = True

        '''
            绝对低估价区域
        '''
        lowest_ma = normal_ma * 0.2
        lowest_high = normal_high * 0.2

        if can_trade:
            # 指定持仓
            account_position = context.account().position(symbol=symbol, side=PositionSide_Long)
            if account_position is None:
                context.trade_stocks.append(symbol)
                print(symbol, "满足建仓条件,已加入股票池")


def take_profit(context):
    # 所有持仓

    account_positions = context.account().positions()
    if len(account_positions) == 0:
        return
    for account_position in account_positions:
        fpnl_rate = account_position.fpnl / account_position.amount * 100
        if fpnl_rate >= 100:
            orders = order_target_value(account_position.symbol, 0, PositionSide_Long, order_type=OrderType_Market,
                                        price=11)
            if len(orders) > 0:
                print(account_position.symbol, "完成止盈或者止损", account_position.fpnl, "盈利率：", fpnl_rate,
                      orders[0])

                print('翻倍平仓', account_position.symbol)


def add_trade_stocks(context):
    account_positions = context.account().positions()
    if len(account_positions) == 0:
        return
    for account_position in account_positions:
        history_data_create = history(symbol=account_position.symbol, frequency='1d',
                                      start_time=account_position.created_at, end_time=account_position.created_at,
                                      fields='close', adjust=ADJUST_PREV, df=True)

        date2 = context.now.strftime("%Y-%m-%d %H:%M:%S")
        history_data_now = history(symbol=account_position.symbol, frequency='1d', start_time=date2, end_time=date2,
                                   fields='close', adjust=ADJUST_PREV, df=True)
        change_rate = (history_data_create.close - history_data_now.close) / history_data_now.close * 100


def trade_stocks(context):
    take_profit(context)
    print(len(context.trade_stocks), "执行交易的股票数量")
    if len(context.trade_stocks) == 0:
        return
    for symbol in context.trade_stocks:
        # 指定持仓
        account_position = context.account().position(symbol=symbol, side=PositionSide_Long)
        if account_position is None:
            print(symbol, "开始建仓")
            order = order_target_value(symbol=symbol, value=10000, position_side=PositionSide_Long,
                                       order_type=OrderType_Market, price=11)
            if len(order) != 0:
                print(symbol, "已经完成建仓，将从建仓股票池剔除该股票")
                context.trade_stocks.remove(symbol)
        else:
            context.trade_stocks.remove(symbol)


def on_error(context, code, info):
    print('code:{}, info:{}'.format(code, info))
    stop()


if __name__ == '__main__':
    '''
        strategy_id策略ID, 由系统生成
        filename文件名, 请与本文件名保持一致
        mode运行模式, 实时模式:MODE_LIVE回测模式:MODE_BACKTEST
        token绑定计算机的ID, 可在系统设置-密钥管理中生成
        backtest_start_time回测开始时间
        backtest_end_time回测结束时间
        backtest_adjust股票复权方式, 不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
        backtest_initial_cash回测初始资金
        backtest_commission_ratio回测佣金比例
        backtest_slippage_ratio回测滑点比例
        '''
    run(strategy_id='aa979b80-e6da-11ec-ba74-0a0027000004',
        filename='估值估价估成本v2.0.py',
        mode=MODE_BACKTEST,
        token='883a7fc43696f3cc100c78b423357976b2ec3352',
        backtest_start_time='2020-11-01 08:00:00',
        backtest_end_time='2020-11-10 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)
